home *** CD-ROM | disk | FTP | other *** search
/ Mac Format 1997 July / macformat52.iso / mac / Shareware Plus / Educational / LEE 2.1 / Source / net.c < prev    next >
Text File  |  1997-04-21  |  16KB  |  819 lines

  1. /* net.c
  2.  *                         Copyright (1992)
  3.  *
  4.  *         Jeff Elman.  University of California, San Diego
  5.  *          Rik Belew.  University of California, San Diego
  6.  *      Stefano Nolfi.  Institute of Psychology, Rome.
  7.  *    Filippo Menczer.  University of California, San Diego
  8.  *
  9.  *        This software may be redistributed without charge;
  10.  *                 this notice should be preserved.
  11.  */
  12.  
  13.  
  14. #include "defs.h"
  15. #include <math.h>
  16.  
  17.  
  18. /*
  19.  ***********************************************************************
  20.  * build_geno_net()
  21.  * build_pheno_net()
  22.  * init_net()
  23.  ***********************************************************************
  24.  * Build a network to specification.
  25.  * We are handed:
  26.  *    - the number of layers,
  27.  *    - the number of elements in each layer, and
  28.  *     - the bounds for random initialization of weights
  29.  * We do:
  30.  *    - create layer pointers and elements
  31.  *    - initialize elements to 0
  32.  *    - create inter-layer weights
  33.  *    - initialize weights to some random value
  34.  */
  35.  
  36. build_geno_net(ip)
  37.  
  38.     struct    indiv *ip;
  39. {
  40.     register int i;
  41.     int    num;
  42.     float    **wp;
  43.     float    **bp;
  44.     int    *ldp;
  45.  
  46.     /*
  47.      * allocate space for backup bias pointers
  48.      */
  49.     ip->iibiasp = (float **) malloc(nlayers * sizeof(float *));
  50.     if (ip->iibiasp == NIL_POINTER)
  51.               {
  52.         printf("\nip->iibiasp malloc\n");
  53.         exit(1);
  54.           }
  55.  
  56.  
  57.     /*
  58.      * allocate space for backup biases
  59.      */
  60.     for (i=0, bp=ip->iibiasp, ldp=layer_descp; i<nlayers; i++, bp++, ldp++)
  61.               {
  62.         *bp = (float *)malloc(*ldp * sizeof(float));
  63.         if (*bp == NIL_POINTER)
  64.                       {
  65.             printf("\nbp malloc\n");
  66.             exit(1);
  67.               }
  68.            }
  69.     /*
  70.      * allocate space for backup weight pointers
  71.      */
  72.     ip->iiweightp =(float **) malloc((nlayers-1) * sizeof(float *));
  73.     if (ip->iiweightp == NIL_POINTER)
  74.                {
  75.         printf("\nip->iiweightp malloc\n");
  76.         exit(1);
  77.            }
  78.     /*
  79.      * ...and for actual backup weights
  80.      * to each unit in layer below)
  81.      */
  82.     for (i=0,wp=ip->iiweightp, ldp=(layer_descp+1); i<(nlayers-1); i++,wp++)
  83.                {
  84.         num = *(ldp + i) * *(ldp + i -1);
  85.         *wp = (float *)malloc(num * sizeof(float));
  86.         if (*wp == NIL_POINTER)
  87.                       {
  88.             printf("\nwp malloc\n");
  89.             exit(1);
  90.               }
  91.             }
  92. }
  93.  
  94.  
  95.  
  96.  
  97.  
  98.  
  99.  
  100.  
  101. build_pheno_net(ip)
  102.  
  103.     struct    indiv *ip;
  104. {
  105.     register int i;
  106.     int    num;
  107.     float    **wp;
  108.     float    **lp;
  109.     float    **dp;
  110.     float    **bp;
  111.     int    *ldp;
  112.  
  113.     /*
  114.      * allocate space for layer pointers
  115.      */
  116.     ip->layerp = (float **) malloc(nlayers * sizeof(float *));
  117.     if (ip->layerp == NIL_POINTER)
  118.               {
  119.         printf("\nip->layerp malloc\n");
  120.         exit(1);
  121.           }
  122.     /*
  123.      * allocate space for layers
  124.      */
  125.     for (i=0, lp=ip->layerp, ldp=layer_descp; i<nlayers; i++, lp++, ldp++)
  126.       {
  127.         /*
  128.          * if our input contains a context copied in from hidden
  129.          * units, we will allocate space for the additional units
  130.          * (Note that the first layer may not be used; we often
  131.          * just point the ip->layerp toward where the input token is
  132.          * stored.).
  133.          */
  134.         *lp = (float *)malloc(*ldp * sizeof(float));
  135.         if (*lp == NIL_POINTER)
  136.                        {
  137.             printf("\nlp malloc\n");
  138.             exit(1);
  139.                }
  140.           }
  141.     /*
  142.      * allocate space for bias pointers
  143.      */
  144.     ip->biasp = (float **) malloc(nlayers * sizeof(float *));
  145.     if (ip->biasp == NIL_POINTER)
  146.               {
  147.         printf("\nip->biasp malloc\n");
  148.         exit(1);
  149.           }
  150.     /*
  151.      * allocate space for biases
  152.      */
  153.     for (i=0, bp=ip->biasp, ldp=layer_descp; i<nlayers; i++, bp++, ldp++)
  154.               {
  155.         *bp = (float *)malloc(*ldp * sizeof(float));
  156.         if (*bp == NIL_POINTER)
  157.                       {
  158.             printf("\nbp malloc\n");
  159.             exit(1);
  160.               }
  161.            }
  162.     /*
  163.      * allocate space for weight pointers
  164.      */
  165.     ip->weightp =(float **) malloc((nlayers-1) * sizeof(float *));
  166.     if (ip->weightp == NIL_POINTER)
  167.                {
  168.         printf("\nip->weightp malloc\n");
  169.         exit(1);
  170.            }
  171.     /*
  172.      * ...and for actual weights (each unit in a given layer connecting
  173.      * to each unit in layer below)
  174.      */
  175.     for (i=0,wp=ip->weightp, ldp=(layer_descp+1); i<(nlayers-1); i++,wp++)
  176.                {
  177.         num = *(ldp + i) * *(ldp + i -1);
  178.         *wp = (float *)malloc(num * sizeof(float));
  179.         if (*wp == NIL_POINTER)
  180.                       {
  181.             printf("\nwp malloc\n");
  182.             exit(1);
  183.               }
  184.             }
  185.     /*
  186.      * allocate space for delta pointers
  187.      */
  188.     ip->deltap = (float **) malloc(nlayers * sizeof(float *));
  189.     if (ip->deltap == NIL_POINTER)
  190.         {
  191.          printf("ERROR : deltap malloc");
  192.          exit(1);
  193.         }
  194.     /*
  195.      * allocate space for deltas
  196.      */
  197.     for (i=0, dp=ip->deltap, ldp=layer_descp; i<nlayers; i++, dp++, ldp++)
  198.         {
  199.          *dp = (float *)malloc(*ldp * sizeof(float));
  200.          if (*dp == NIL_POINTER)
  201.         {
  202.          printf("ERROR : dp malloc");
  203.          exit(1);
  204.         }
  205.         }        
  206.  
  207. }
  208.  
  209. init_net(ip)
  210.  
  211.     struct    indiv *ip;
  212. {
  213.     register int i;
  214.     register int j;
  215.     int    num;
  216.     float    **wp;
  217.     float    **iiwp;
  218.     float    **bp;
  219.     float    **iibp;
  220.     int    *ldp;
  221.     float   *w;
  222.     float   *iiw;
  223.     float   *b;
  224.     float   *iib;
  225.  
  226.     /*
  227.      * initialize biases
  228.      */
  229.     for (i=0, bp=ip->biasp, iibp=ip->iibiasp, ldp=layer_descp; 
  230.         i < nlayers; 
  231.         i++, bp++, ldp++, iibp++)
  232.     {
  233.         for (j=0, b= *bp, iib= *iibp; j < *ldp; j++, b++, iib++)
  234.         {
  235.             *b = 0.0;
  236.             *iib = *b;
  237.         }
  238.     }
  239.     
  240.     /*
  241.      * initialize weights randomly
  242.      */
  243.     for (i=0, wp=ip->weightp, iiwp=ip->iiweightp, ldp=layer_descp; 
  244.         i < (nlayers-1);
  245.         i++, wp++, iiwp++, ldp++)
  246.     {
  247.         num = *(ldp) * *(ldp + 1);
  248.         for (j=0, w = *wp, iiw = *iiwp;  j < num; j++, w++, iiw++)
  249.         {
  250.             *w = rans(weight_limit);
  251.             *iiw = *w;
  252.         }
  253.     }
  254. }
  255.  
  256.  
  257. destroy_network(ip)
  258.  
  259.     struct    indiv *ip;
  260. {
  261.     register int i;
  262.     float    **wp;
  263.     float    **lp;
  264.     float    **dp;
  265.     float    **bp;
  266.  
  267.     
  268.  
  269.         /*
  270.          * we free biases and pointers (geno and pheno)
  271.          */
  272.     for (i=0, bp=ip->biasp; i<nlayers; i++, bp++)
  273.                {
  274.          if (*bp)
  275.                     {
  276.                free((char *)*bp);
  277.             }
  278.            }
  279.     if (ip->biasp)
  280.                {
  281.           free((char *)ip->biasp);
  282.            }
  283.     for (i=0, bp=ip->iibiasp; i<nlayers; i++, bp++)
  284.                {
  285.          if (*bp)
  286.                     {
  287.                free((char *)*bp);
  288.             }
  289.            }
  290.     if (ip->iibiasp)
  291.                {
  292.           free((char *)ip->iibiasp);
  293.            }
  294.         /*
  295.          * we free weights and pointers (geno and pheno)
  296.          */
  297.      for (i=0, wp=ip->weightp; i<(nlayers-1); i++,wp++)
  298.                 {
  299.           if (*wp)
  300.                        {
  301.              free((char *)*wp);
  302.                }
  303.             }
  304.      if (ip->weightp)
  305.                 {
  306.           free((char *)ip->weightp);
  307.             }
  308.      for (i=0, wp=ip->iiweightp; i<(nlayers-1); i++,wp++)
  309.                 {
  310.           if (*wp)
  311.                        {
  312.              free((char *)*wp);
  313.                }
  314.             }
  315.      if (ip->iiweightp)
  316.                 {
  317.           free((char *)ip->iiweightp);
  318.             }
  319.         /*
  320.          * we free layers and pointers
  321.          */
  322.      for (i=0, lp=ip->layerp; i<nlayers; i++, lp++)
  323.                 {
  324.            if (*lp)
  325.                        {
  326.              free((char *)*lp);
  327.                 }
  328.             }
  329.      if (ip->layerp)
  330.             free((char *)ip->layerp);
  331.         /*
  332.          * we free deltas and pointers
  333.          */
  334.      for (i=0, dp=ip->deltap; i<nlayers; i++, dp++)
  335.                 {
  336.            if (*dp)
  337.                        {
  338.              free((char *)*dp);
  339.                 }
  340.             }
  341.      if (ip->deltap)
  342.             free((char *)ip->deltap);
  343.  
  344.      ip->layerp = ip->deltap = 0;
  345.      ip->weightp = ip->biasp = 0;
  346.      ip->iiweightp = ip->iibiasp = 0;
  347. }
  348.  
  349. /*
  350.  ***********************************************************************
  351.  * activate_net
  352.  ***********************************************************************
  353.  */
  354. activate_net(ip)
  355.  
  356.        struct indiv *ip;
  357.  
  358. {
  359.     register int i;
  360.     float **wp;
  361.     float **bp;
  362.     float **lp;
  363.     int    *ldp;
  364.  
  365.     wp = ip->weightp;
  366.     lp = ip->layerp;
  367.     bp = ip->biasp;
  368.     ldp = layer_descp;
  369.  
  370.     for (i = 0; i < (nlayers - 1); i++)
  371.          {
  372.            act(*lp, *ldp, *(lp + 1), *(ldp + 1), *wp, *(bp + 1));
  373.            ldp++;
  374.            lp++;
  375.            wp++;
  376.            bp++;
  377.           }
  378.     
  379. }
  380.  
  381.  
  382. /*
  383.  * Allow units in one layer to activate the next one. Arguments:
  384.  * sending layer pointer, sending layer size, receving layer pointer,
  385.  * receiving layer size, weights pointer, receiving layer bias pointer
  386.  */
  387.  
  388. act(b_actp, b_size, t_actp, t_size, t_weightp, t_biasp)
  389.     float    *b_actp;
  390.     int    b_size;
  391.     float    *t_actp;
  392.     int    t_size;
  393.     register float *t_weightp;
  394.     float    *t_biasp;
  395. {
  396.     register float *bap;
  397.     register float *endp;
  398.     register float net;
  399.     register int t;
  400.  
  401.     /*
  402.      * Activate Propagation Up Network
  403.      */
  404.     endp = b_actp + b_size;
  405.     for (t = 0; t < t_size; t++)
  406.     {
  407.         net = 0.0;
  408.         bap = b_actp;
  409.         while (bap < endp)
  410.         {
  411.             net += *t_weightp++ * *bap++;
  412.         }
  413.         net += *t_biasp;
  414.         if (net < -10.0)
  415.             *t_actp = 0.0;
  416.         else if (net > 10.0)
  417.             *t_actp = 1.0;
  418.         else
  419.             *t_actp = logistic(net);
  420.         t_actp++;
  421.         t_biasp++;
  422.     }
  423. }
  424.  
  425.  
  426.  
  427.  
  428. /*
  429.  * load in memory the sigmoid table 
  430.  * (only for positive values): it takes ~40K
  431.  */
  432.  
  433. void
  434. carica_sigmoide()
  435. {
  436.  int i;
  437.  
  438.  for (i=0;i<=NSIGMA;i++)
  439.    {
  440.     sigmoide[i] = (1.0 / (1.0 + (float)exp(-((double)i / LOG_RES))));
  441.    }
  442. }
  443.  
  444.  
  445.  
  446. /*
  447.  * (unused) standard logistic function: logistic() used instead
  448.  */
  449. float
  450. clogistic(f)
  451.  
  452.   float f;
  453.  
  454. {
  455.     return(1.0 / (1.0 + (float)exp((double)(-f))));
  456. }
  457.  
  458. /*
  459.  * logistic functions: uses values stored in sigmoid table
  460.  */
  461. float
  462. logistic(neti)
  463.  
  464.    float neti;
  465. {
  466.    int i;
  467.  
  468.    i = (int)(neti * LOG_RES);
  469.    if (i >=0)
  470.       return(sigmoide[i]);
  471.    else
  472.       return(1.0 - sigmoide[-i]);
  473. }
  474.  
  475.  
  476. /*
  477.  ***********************************************************************
  478.  * update_net
  479.  ***********************************************************************
  480.  */
  481.  
  482.  
  483. /*
  484.  *  update weights according to Arp algorithm (RL)
  485.  */
  486. r_learn(ip,r)
  487.  
  488.     struct indiv *ip;
  489.     float  r; /* reinforcement signal <> 0 */
  490. {
  491.     float  **lp;
  492.     float  **wp;
  493.     float  **dp;
  494.     float  **bp;
  495.     int    *ldp;
  496.     register int i,j,k;
  497.     int     nl;
  498.     float temp;
  499.  
  500.     float teachp[NOUTPUTS];
  501.  
  502.      nl = nlayers - 1;
  503.  
  504.      /*
  505.       * do layers in reverse; output layer is done differently
  506.       */
  507.       ldp = layer_descp + nl;
  508.       lp = ip->layerp + nl;
  509.       dp = ip->deltap + nl;
  510.       wp = ip->weightp + (nl - 1);
  511.  
  512.     if (r > 0.0)
  513.         for (i=0;i<*ldp;i++) 
  514.             teachp[i] = (*(*lp+i)>0.5)?1.0:0.0;
  515.     else if (r < -(2.0 * ENERGY_USE))
  516.         for (i=0;i<*ldp;i++) 
  517.             teachp[i] = (*(*lp+i)>0.5)?0.0:1.0;
  518.     else return;
  519.  
  520.     for (i=0;i<*ldp;i++) 
  521.         *(*dp+i) = teachp[i] - *(*lp+i);
  522.  
  523.        /*
  524.         * do the rest nlayers-2
  525.         */
  526.         for (i = nl-1 ; i > 0; i--)
  527.          {
  528.         for (j=0;j<*(ldp-1);j++)
  529.         {
  530.             temp = 0.0;
  531.             for (k=0;k<*ldp;k++)
  532.                 temp += *(*dp+k) * (*(*wp+(*(ldp-1)*k)+j));
  533.             *(*(dp-1)+j) = temp;
  534.  
  535.         }
  536.         ldp--;
  537.         dp--;
  538.         wp--;
  539.           }
  540.         /*
  541.          * update the weights and biases, given the deltas
  542.          * we just computed
  543.          */
  544.          ldp = layer_descp + nl;
  545.          lp = ip->layerp + nl;
  546.          wp = ip->weightp + (nl - 1);
  547.          dp = ip->deltap + nl;
  548.          bp = ip->biasp + nl;
  549.          for (i = 0; i < nl; i++)
  550.           {
  551.            upd_weight(*ldp, *dp, *wp, *bp, *(lp - 1), *(ldp - 1));
  552.            ldp--;
  553.            dp--;
  554.            wp--;
  555.            bp--;
  556.            lp--;
  557.           }
  558.     
  559. }
  560.  
  561.  
  562.  
  563. /*
  564.  *  update weights according to Prediction Learning algorithm
  565.  */
  566. update_net(ip,teachp)
  567.  
  568.     struct indiv *ip;
  569.     float  *teachp;
  570. {
  571.     float  **lp;
  572.     float  **wp;
  573.     float  **dp;
  574.     float  **bp;
  575.     int    *ldpin, *ldp;
  576.     register int i;
  577.     int     nl;
  578.  
  579.  
  580.      nl = nlayers - 1;
  581.      /*
  582.       * do layers in reverse; output layer is done differently
  583.       */
  584.       ldpin = layer_descp;
  585.       ldp = layer_descp + nl;
  586.       lp = ip->layerp + nl;
  587.       dp = ip->deltap + nl;
  588.       wp = ip->weightp + (nl - 1);
  589.       delta_out(*lp, *ldpin, *ldp, teachp, *dp);
  590.        /*
  591.         * do the rest for nl-1 (==nlayers-2);  we only have
  592.         * (nlayers-1) connections to change, and we've already done
  593.         * top set
  594.         */
  595.  
  596.         for (i = 0; i < (nl - 1); i++)
  597.          {
  598.             delta(*ldp, *dp, *wp, *(lp - 1), *(ldp - 1), *(dp - 1));
  599.         lp--;
  600.         ldp--;
  601.         dp--;
  602.         wp--;
  603.           }
  604.         /*
  605.          * go back and update the weights and biases, given the deltas
  606.          * we just computed
  607.          */
  608.          ldp = layer_descp + nl;
  609.          lp = ip->layerp + nl;
  610.          wp = ip->weightp + (nl - 1);
  611.          dp = ip->deltap + nl;
  612.          bp = ip->biasp + nl;
  613.          for (i = 0; i < nl; i++)
  614.           {
  615.            upd_weight(*ldp, *dp, *wp, *bp, *(lp - 1), *(ldp - 1));
  616.            ldp--;
  617.            dp--;
  618.            wp--;
  619.            bp--;
  620.            lp--;
  621.           }
  622.     
  623. }
  624.  
  625.  
  626.  
  627.  
  628. /*
  629.  * update weights
  630.  * for each weights layer it takes :
  631.  * the size of the receiving layer, the delta of the receiving layer,
  632.  * the weights layer, the bias layer
  633.  * the sending units layer and the sending units layer size.
  634.  */
  635.  
  636. upd_weight(t_size, t_deltap, t_weightp, t_biasp, b_actp, b_size)
  637.  
  638.     int    t_size;
  639.     register float *t_deltap;
  640.     register float *t_weightp;
  641.     float    *t_biasp;
  642.     float    *b_actp;
  643.     int    b_size;
  644. {
  645.     register float *bap;
  646.     register float *endp;
  647.     register float r_rate = rate;
  648.     register float dp_rate;
  649.     register int t;
  650.  
  651.     endp = b_actp + b_size;
  652.     for (t=0; t<t_size; t++)
  653.         {
  654.           bap = b_actp;
  655.           dp_rate = *t_deltap++ * r_rate;
  656.           while (bap < endp)
  657.         {
  658.            *t_weightp++ += *bap++ * dp_rate;
  659.         }
  660.           *t_biasp++ += dp_rate;
  661.             }
  662.  
  663. }
  664.  
  665.  
  666.  
  667.  
  668.  
  669.  
  670.  
  671. /*
  672.  * computes error and deltas of the output layer
  673.  * it takes the output layer, the size of input/output layers,
  674.  * the teaching input pointer and the delta of the last layer
  675.  */
  676. delta_out(outp, insize, outsize, tarp, outdeltap)
  677.     register float *outp;
  678.     register int insize;
  679.     register int outsize;
  680.     register float *tarp;
  681.     register float *outdeltap;
  682. {
  683.     register int i;
  684.     register float out;
  685.     register float diff;
  686.  
  687.     global_error = 0;
  688.  
  689. /********************************************
  690.  * RIK: when the bug correction is moved
  691.  *      from here to update_net(), the
  692.  *      following is the original code...
  693.  ********************************************
  694.  
  695.     for (i=0; i<outsize; i++)
  696.         {
  697.          out = *outp;
  698.          diff = (*tarp - out);
  699.          if (*tarp <= -999999999.0)
  700.             diff = 0.0;
  701.          *outdeltap = diff * out * (1. - out);
  702.          global_error += diff*diff;
  703.          outdeltap++;
  704.          outp++;
  705.          tarp++;
  706.         }
  707.  
  708. ***********************************************
  709. *    while the following is the 
  710. *    temporary hack substituted for it...
  711. *    note: outp is incremented in order to
  712. *        align teaching pattern 
  713. *        and prediction output units
  714. ***********************************************/
  715.  
  716.     for (i=insize; i<outsize; i++)
  717.     {
  718.         *outdeltap = 0.0;
  719.         outdeltap++;
  720.              outp++;
  721.     }
  722.     for (i=0; i<insize; i++)
  723.     {
  724.         out = *outp;
  725.              diff = (*tarp - out);
  726.              if (*tarp <= -999999999.0)
  727.             diff = 0.0;
  728.              *outdeltap = diff * out * (1.0 - out);
  729.              global_error += diff*diff;
  730.              outdeltap++;
  731.              outp++;
  732.              tarp++;
  733.     }
  734.  
  735. /************************************************
  736.  *    END OF HACK - Fil
  737.  ************************************************/
  738. }
  739.  
  740.  
  741.  
  742.  
  743.  
  744.  
  745. /*
  746.  * computes delta for all the layer but the output.
  747.  * for each layer of weights it takes :
  748.  *  the size of units of the receiving layer, deltas of the receiving layer,
  749.  *  the layer weights, the units of the sending layer, the size of the
  750.  *  sending layer and delta of the sending layer.
  751.  */
  752. delta(t_size, t_deltap, t_weightp, b_actp, b_size, b_deltap)
  753.     register int t_size;
  754.     register float *t_deltap;
  755.     register float *t_weightp;
  756.     register float *b_actp;
  757.     register int b_size;
  758.     float    *b_deltap;
  759. {
  760.     register float tmp;
  761.     register float *tdp;
  762.     register int t;
  763.     register int b;
  764.  
  765.     for (b=0; b<b_size; b++)
  766.         {
  767.           tmp = 0;
  768.           for (t=0, tdp=t_deltap; t<t_size; t++, tdp++)
  769.           {
  770.             tmp += *tdp * *(t_weightp + (t*b_size) + b);
  771.           }
  772.           *b_deltap = (1.-*b_actp) * *b_actp * tmp;
  773.           b_deltap++;
  774.           b_actp++;
  775.        }
  776. }
  777.  
  778.  
  779.  
  780.  
  781.  
  782.  
  783.  
  784. /*
  785.  * print input and output activation values
  786.  */
  787.  
  788.  
  789. print_out(ap,cycle)
  790.  
  791.       struct indiv *ap;
  792.       int cycle;
  793.  
  794. {
  795.  
  796.       int i;
  797.       float **lp;
  798.       float *l;
  799.  
  800.       lp = ap->layerp;
  801.       printf("cycle: %d ",cycle);
  802.       printf("in: ");
  803.       for(i=0,l = *lp;i < *layer_descp;i++,l++)
  804.         {
  805.            printf("%.2f ",*l);
  806.         }
  807.       lp = ap->layerp;
  808.       lp = (lp + (nlayers - 1));
  809.       printf("ou: ");
  810.       for(i=0,l = *lp;i < *(layer_descp+nlayers-1);i++,l++)
  811.         {
  812.            printf("%.2f ",*l);
  813.         }
  814.       printf("\n");
  815.  
  816. }
  817.  
  818.  
  819.